package de.playmee.geo;

import com.google.android.maps.GeoPoint;

import de.playmee.Channel;

public class Region {
	
	public static float EARTH_RADIUS_METERS = 6367000;
	public static float EPSILON = 0.0001f;
	
	private GeoPoint center;
	private float meters;
	private String title = "";
	private long id;
	private Channel channel;
	
	public Region() {};
	public Region(float latitude, float longitude, float meters) {
		center = new GeoPoint((int)(latitude*1E6), (int)(longitude*1E6));
		this.meters = meters;
	}
	public Region(float latitude, float longitude, float meters, String title) {
		center = new GeoPoint((int)(latitude*1E6), (int)(longitude*1E6));
		this.meters = meters;
		this.title = title;
	}
	public Region(GeoPoint geoPoint, float meters) {
		center = geoPoint;
		this.meters = meters;
	}
	public Region(GeoPoint geoPoint, float meters, String title) {
		center = geoPoint;
		this.meters = meters;
		this.title = title;
	}
	public float getLatitude() {
		return (float)(center.getLatitudeE6()/1E6);
	}
	public float getLongitude() {
		return (float)(center.getLongitudeE6()/1E6);
	}
	public float getMeters() {
		return meters;
	}
	public void setMeters(float meters) {
		this.meters = meters;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public void setCenter(GeoPoint geoPoint) {
		center = geoPoint;
	}
	public GeoPoint getCenter() {
		return center;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
//	public void setPriorityList(LinkedList<Channel> priorityList) {
//		this.priorityList = priorityList;
//	}
//	public LinkedList<Channel> getPriorityList() {
//		return priorityList;
//	}
	
	public void setChannel(Channel channel) {
		this.channel = channel;
	}
	public Channel getChannel() {
		return channel;
	}
	
	/**
	 * isOnThisRegion checks whether the point given by the latitude and longitude is located on this region (circle)
	 * projected on the earth by comparing the distance between the given point and the center of this circle and the radius
	 * 
	 * @param latitude
	 * @param longitude
	 * @return
	 */
	public boolean isOnThisRegion(float latitude, float longitude) {
		return getDistance(latitude, longitude, ((float)(center.getLatitudeE6()/1E6)), ((float)(center.getLongitudeE6()/1E6))) < meters + EPSILON;
	}
	
	/**
	 * Returns the distance from a point to this region
	 * 
	 * @param point
	 * @return distance
	 */
	public float getDistance(GeoPoint point) {
		return Region.getDistance((float) (center.getLatitudeE6() / 1E6), (float) (center.getLongitudeE6() / 1E6), (float) (point.getLatitudeE6() / 1E6), (float) (point.getLongitudeE6() / 1E6));
	}
	
	/**
	 * getDistance computes the distance between the two coordinates (latitude_1, longitude_1) and (latitude_2, longitude_2)
	 * 	according to the Harversine formula
	 * 
	 * @param latitude_p1: Latitude from first point
	 * @param longitude_p1: Longitude from first point
	 * @param latitude_p2: Latitude from second point
	 * @param longitude_p2: Longitude from second point
	 * @return distance between the two points
	 */
	public static float getDistance(float latitude_p1, float longitude_p1, float latitude_p2, float longitude_p2) {
		float lat1_rad = (float)Math.toRadians(latitude_p1), lat2_rad = (float)Math.toRadians(latitude_p2), long1_rad = (float)Math.toRadians(longitude_p1), long2_rad = (float)Math.toRadians(longitude_p2);
		float term1 = (float)Math.sin((lat2_rad - lat1_rad)/2);
		term1 = term1 * term1;
		float term2 = (float)(Math.sin((long2_rad - long1_rad)/2)); term2 = term2*term2;
		term2 = (float) (Math.cos(lat1_rad)*Math.cos(lat2_rad)*term2);
		return 2.f * EARTH_RADIUS_METERS * ((float)(Math.asin(Math.min(1, Math.sqrt(term1 + term2)))));
	}
}
